package com.itita.ww2.model.worldmap;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.joda.time.DateTime;

import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.itita.ww2.data.BuildingConfig;
import com.itita.ww2.data.WorldMapConfig;
import com.itita.ww2.game.worldmap.WorldMapManager;
import com.itita.ww2.model.worldmap.enums.StatusEnum;
import com.itita.ww2.redis.RedisUtil;
import com.itita.ww2.redis.cache.Table;
import com.itita.ww2.utils.DataUtil;
import com.itita.ww2.utils.TimeUtil;
import com.smartfoxserver.v2.entities.data.ISFSArray;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;

/**
 * 据点
 * @author NorthLan
 */
public class Base {
	private int blockId; // blockId
	private int cityId; // cityId
	private int baseId; // baseId
	private City parentCity;
	// 
	private int underAtkUid = -1;
	private Table table;
	//
	private DateTime lastOccTime;
	private DateTime lastAtkTime;
	private int ownerUid = -1;
	private int level = 1;

	public Base(int baseId, City parentCity) {
		this.baseId = baseId;
		this.cityId = parentCity.getId();
		this.blockId = parentCity.getParentBlock().getId();
		this.parentCity = parentCity;
		this.table = WorldMapManager.getInstance().getCacheBaseTable();
		initData();
	}

	private void initData() {
		this.lastOccTime = DataUtil
				.timeValueOf(table.getValue(RedisUtil.genericKey(blockId, cityId, baseId), "lastOccTime"));
		this.lastAtkTime = DataUtil
				.timeValueOf(table.getValue(RedisUtil.genericKey(blockId, cityId, baseId), "lastAtkTime"));
		this.ownerUid = DataUtil.intValueOf(table.getValue(RedisUtil.genericKey(blockId, cityId, baseId), "ownerUid"));
		this.level = DataUtil.intValueOf(table.getValue(RedisUtil.genericKey(blockId, cityId, baseId), "level"));
	}

	public StatusEnum getStatus() {
		if (underAtkUid != -1) {
			return StatusEnum.UNDER_ATTACK;
		}
		//		else if (getOwnerUid() != -1) {
		//			return StatusEnum.OCCUPIED;
		//		}
		return StatusEnum.DEFAULT;
	}

	/**
	 * 设定据点被攻击
	 */
	public void underAttack(int uid) {
		underAtkUid = uid;
		setLastAtkTime(TimeUtil.getUtcNow());
	}

	/**
	 * 据点被占领
	 */
	public void occupied(int uid) {
		resetUnderAtk();
		setOwnerUid(uid);
		setLastOccTime(TimeUtil.getUtcNow());
	}

	public void resetUnderAtk() {
		this.underAtkUid = -1;
	}

	/**
	 * 重置为默认
	 */
	public void reset() {
		resetUnderAtk();
		setOwnerUid(-1);
		setLastAtkTime(null);
		setLastOccTime(null);
	}

	/**
	 * 据点是否可以升级
	 */
	public boolean canUpgrade() {
		int maxLv = WorldMapConfig.getBaseMaxLevel();
		return getLevel() < maxLv;
	}

	/**
	 * 据点地图是否还可以强化
	 */
	public boolean canEnhance() {
		ISFSObject mapData = getMap();
		ISFSArray map = mapData.getSFSArray("map");
		ISFSObject list = mapData.getSFSObject("list");
		// 梯度
		List<Integer> gradientConfig = WorldMapConfig.getBaseBDGradient();
		// 所有据点数量全部变为最强就不能强化
		return list.getInt(String.valueOf(gradientConfig.get(0))) != map.size();
	}

	/**
	 * 获取此据点当前升级所需资源
	 */
	public ISFSObject getUpgradeResource() {
		// 获取据点地图
		ISFSObject baseMapList = getMap().getSFSObject("list");
		// mapping
		ISFSObject bdMapping = WorldMapConfig.getBaseMapping();
		// 据点等级(所有建筑物等级)
		int baseLv = getLevel();
		ISFSObject resObj = SFSObject.newInstance();
		// 当前升级所需资源
		for (String key : baseMapList.getKeys()) {
			// 根据建筑类别,计算价格
			String bdCode = bdMapping.getUtfString(key);// + "_" + baseLv;
			int count = baseMapList.getInt(key);
			// 获取对应资源以及种类
			ISFSObject bRes = BuildingConfig.getBDBaseUpgradeRes(bdCode, baseLv);
			for (String resKey : bRes.getKeys()) {
				if (!resObj.containsKey(resKey)) {
					resObj.putInt(resKey, 0);
				}
				resObj.putInt(resKey, resObj.getInt(resKey) + bRes.getInt(resKey) * count);
			}
		}
		return resObj;
	}

	/**
	 * 获取据点强化所需资源
	 */
	public ISFSObject getEnhanceResource() {
		// 强弱梯度
		List<Integer> gradientConfig = WorldMapConfig.getBaseBDGradient();
		// maplist
		ISFSObject mapList = getMap().getSFSObject("list");
		// mapping
		ISFSObject mapping = WorldMapConfig.getBaseMapping();
		// 倒序,从最弱的开始
		int toType = gradientConfig.get(0);
		int level = getLevel();
		for (int i = gradientConfig.size() - 1; i > 0; --i) { // 第一位不取
			int type = gradientConfig.get(i);
			if (mapList.containsKey(String.valueOf(type)) && mapList.getInt(String.valueOf(type)) > 0) {
				// 取最高等级升级到N的价格即可
				String bdCode = mapping.getUtfString(String.valueOf(toType));
				return WorldMapConfig.getSingleBaseBDResSum(bdCode, level);
			}
		}
		return SFSObject.newInstance();
	}

	/**
	 * 升级捐献(返回是否升级)
	 */
	public boolean upgradeDonate(ISFSObject resObj) {
		Map<String, Long> m_BaseRes = getUpgradeDonateResource();
		for (String key : resObj.getKeys()) {
			if (!m_BaseRes.containsKey(key)) {
				m_BaseRes.put(key, 0L);
			}
			m_BaseRes.put(key, m_BaseRes.get(key) + resObj.getInt(key));
		}
		setUpgradeDonateResource(m_BaseRes);
		// 以下是升级
		ISFSObject needObj = getUpgradeResource();
		Map<String, Long> donateObj = getUpgradeDonateResource();
		for (String key : needObj.getKeys()) {
			long needRes = needObj.getInt(key);
			if (donateObj.containsKey(key)) {
				long nowRes = donateObj.get(key);
				if (nowRes < needRes) {
					return false;
				} else {
					donateObj.put(key, nowRes - needRes);
				}
			} else {
				return false;
			}
		}
		// 升级,不能高过最大等级
		int nowLevel = getLevel();
		if (nowLevel == WorldMapConfig.getBaseMaxLevel()) {
			return false;
		}
		setUpgradeDonateResource(donateObj); // 设置为新值
		setLevel(nowLevel + 1);
		return true;
	}

	/**
	 * 强化捐献(返回是否强化)
	 */
	public boolean enhanceDonate(ISFSObject resObj) {
		Map<String, Long> m_BaseRes = getEnhanceDonateResource();
		for (String key : resObj.getKeys()) {
			if (!m_BaseRes.containsKey(key)) {
				m_BaseRes.put(key, 0L);
			}
			m_BaseRes.put(key, m_BaseRes.get(key) + resObj.getInt(key));
		}
		setEnhanceDonateResource(m_BaseRes);
		// 判断强化条件,自动强化
		ISFSObject needObj = getEnhanceResource();
		if (needObj.size() <= 0) {
			return false;
		}
		Map<String, Long> donateObj = getEnhanceDonateResource();
		for (String key : needObj.getKeys()) {
			long needRes = needObj.getInt(key);
			if (donateObj.containsKey(key)) {
				long nowRes = donateObj.get(key);
				if (nowRes < needRes) {
					return false;
				} else {
					donateObj.put(key, nowRes - needRes);
				}
			} else {
				return false;
			}
		}
		// 条件满足,强化
		// 强弱梯度
		List<Integer> gradientConfig = WorldMapConfig.getBaseBDGradient();
		// map
		ISFSObject map = getMap();
		ISFSObject mapList = map.getSFSObject("list");
		ISFSArray mapdata = map.getSFSArray("map");
		// 倒序,从最弱的开始
		int toType = gradientConfig.get(0);
		for (int i = gradientConfig.size() - 1; i > 0; --i) { // 第一位不取
			int type = gradientConfig.get(i);
			if (mapList.containsKey(String.valueOf(type)) && mapList.getInt(String.valueOf(type)) > 0) {
				// 把type修改为toType即可
				int newCount = mapList.getInt(String.valueOf(type)) - 1;
				newCount = newCount < 0 ? 0 : newCount;
				mapList.putInt(String.valueOf(type), newCount);
				mapList.putInt(String.valueOf(toType), mapList.getInt(String.valueOf(toType)) + 1);
				// 
				for (int k = 0; k < mapdata.size(); ++k) {
					ISFSObject mapItem = mapdata.getSFSObject(k);
					if (mapItem.getInt("type") == type) {
						mapItem.putInt("type", toType);
						break;
					}
				}
				// map要设置一下
				setMap(map);
				break;
			}
		}
		setEnhanceDonateResource(donateObj); // 设置为新值
		return true;
	}

	////////////////////////////////////////////////
	private Map<String, Long> getUpgradeDonateResource() {
		String str = table.getValue(RedisUtil.genericKey(blockId, cityId, baseId), "upgrade_donate");
		Map<String, Long> ret = new GsonBuilder().create().fromJson(str, new TypeToken<Map<String, Long>>() {
		}.getType());
		if (ret == null) {
			ret = new HashMap<>();
		}
		return ret;
	}

	public ISFSObject getUpgradeDonateResourceObj() {
		String str = table.getValue(RedisUtil.genericKey(blockId, cityId, baseId), "upgrade_donate");
		return DataUtil.objValueOf(str);
	}

	public void setUpgradeDonateResource(Map<String, Long> data) {
		table.setValue(RedisUtil.genericKey(blockId, cityId, baseId), "upgrade_donate",
				new GsonBuilder().create().toJson(data));
	}

	public Map<String, Long> getEnhanceDonateResource() {
		String str = table.getValue(RedisUtil.genericKey(blockId, cityId, baseId), "enhance_donate");
		Map<String, Long> ret = new GsonBuilder().create().fromJson(str, new TypeToken<Map<String, Long>>() {
		}.getType());
		if (ret == null) {
			ret = new HashMap<>();
		}
		return ret;
	}

	public ISFSObject getEnhanceDonateResourceObj() {
		String str = table.getValue(RedisUtil.genericKey(blockId, cityId, baseId), "enhance_donate");
		return DataUtil.objValueOf(str);
	}

	public void setEnhanceDonateResource(Map<String, Long> data) {
		table.setValue(RedisUtil.genericKey(blockId, cityId, baseId), "enhance_donate",
				new GsonBuilder().create().toJson(data));
	}

	public DateTime getLastOccTime() {
		return this.lastOccTime;
	}

	public void setLastOccTime(DateTime time) {
		this.lastOccTime = time;
		String ret = "";
		if (time != null) {
			ret = time.toString(TimeUtil.redisTimestampFormatter);
		}
		table.setValue(RedisUtil.genericKey(blockId, cityId, baseId), "lastOccTime", ret);
	}

	public DateTime getLastAtkTime() {
		return this.lastAtkTime;
	}

	public void setLastAtkTime(DateTime time) {
		this.lastAtkTime = time;
		String ret = "";
		if (time != null) {
			ret = time.toString(TimeUtil.redisTimestampFormatter);
		}
		table.setValue(RedisUtil.genericKey(blockId, cityId, baseId), "lastAtkTime", ret);
	}

	public int getOwnerUid() {
		return this.ownerUid;
	}

	public void setOwnerUid(int uid) {
		this.ownerUid = uid;
		table.setValue(RedisUtil.genericKey(blockId, cityId, baseId), "ownerUid", uid);
	}

	public int getLevel() {
		return this.level;
	}

	public void setLevel(int level) {
		this.level = level;
		table.setValue(RedisUtil.genericKey(blockId, cityId, baseId), "level", level);
	}

	public ISFSObject getMap() {
		return DataUtil.objValueOf(table.getValue(RedisUtil.genericKey(blockId, cityId, baseId), "mapdata"));
	}

	public void setMap(ISFSObject data) {
		table.setValue(RedisUtil.genericKey(blockId, cityId, baseId), "mapdata", data.toJson());
	}

	public int getId() {
		return baseId;
	}

	public City getParentCity() {
		return parentCity;
	}

	public final int getUnderAtkUid() {
		return underAtkUid;
	}

	public final int getBlockId() {
		return blockId;
	}

	public final int getCityId() {
		return cityId;
	}

}
